home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / shells / scsh-0.4 / scsh-0 / scsh-0.4.2 / scsh / putenv.c < prev    next >
C/C++ Source or Header  |  1995-10-26  |  5KB  |  182 lines

  1. /* My very own implementation of putenv() and friends,
  2. ** because NeXTSTEP is a lame UNIX.
  3. **
  4. ** Copyright (c) 1994 by Olin Shivers.
  5. ** You may use this software for any purpose provided I am not held
  6. ** accountable for its effects and you leave this copyright notice
  7. ** intact.
  8. */
  9.  
  10. /* This file exports three names:
  11. **     extern int putenv(const char *str);
  12. **     extern int unsetenv(const char *name);
  13. **     extern int setenv(const char *name, const char *val);
  14. */
  15.  
  16. /* This code leaks memory. It is unavoidable. */
  17.  
  18. #include <string.h>
  19.  
  20. /* Don't want to include stdlib.h because it declares putenv to take
  21. ** a const string -- bogus. So we'll just declare malloc directly.
  22. */
  23. extern void *malloc(size_t size);
  24.  
  25. #define Malloc(type,n)    ((type *) malloc(sizeof(type)*(n)))
  26.  
  27. extern char **environ;
  28. /*****************************************************************************/
  29.  
  30. /* Internal utility.
  31. ** Copy the entire env to a new block, and add the new definition.
  32. ** Drop the old block on the floor; can't free() it.
  33. ** Return 0 if win
  34. **        non-zero if the malloc fails.
  35. */
  36. static int append_envvar(char *str, int old_envsize)
  37. {
  38.     char **envp, **nenvp;
  39.     char **newenv = Malloc(char*, 1+old_envsize);
  40.     if( !newenv ) return 1;
  41.  
  42.     for( envp=environ, nenvp=newenv;   *envp;   envp++, nenvp++ )
  43.     *nenvp = *envp;
  44.     *nenvp++ = str;
  45.     *nenvp = 0;
  46.     environ = newenv;
  47.     return 0;
  48.     }
  49.  
  50.  
  51. /* int putenv(char *str)
  52. ***************************
  53. ** Change or add a value to the environment.
  54. **
  55. ** str is an env string of the form "<var>=<val>".
  56. ** The environ vector is scanned for a matching <var> binding.
  57. ** If one is found, str is installed in that slot in the vector.
  58. ** Otherwise, the environ vector is copied into a new vector of one greater
  59. ** size, and str is added in the new slot. Note: in either case, str
  60. ** becomes part of the environment structure (until is later replaced by
  61. ** another putenv() call), so altering str changes the environment.
  62. **
  63. ** Malloc is used to allocate new environ vectors. 
  64. ** In neither replacement strategy are we able to free() the unused
  65. ** storage; it is simply dropped on the floor.
  66. ** Putenv returns
  67. **   0 if it wins;
  68. **   non-zero if str doesn't contain an '=' char or if the malloc fails.
  69. */
  70.  
  71. int putenv(char *str)
  72. {
  73.     char **envp;
  74.     char *equalsign = strchr(str, '=');
  75.     int namelen;
  76.  
  77.     if( ! equalsign ) return 0; /* No equals sign in str! */
  78.     namelen = 1 + equalsign - str; /* Count the terminating =. */
  79.  
  80.     for(envp = environ; *envp; envp++)
  81.     if( ! memcmp(*envp, str, namelen) ) {
  82.         *envp = str;
  83.         return 0;
  84.         }
  85.  
  86.     /* The env var wasn't defined. Copy the entire env to a new
  87.     ** block, and add the new definition.
  88.     */
  89.     return append_envvar(str, envp-environ+1);
  90.     }
  91.  
  92.  
  93. /* int unsetenv(const char *name)
  94. ***********************************   
  95. ** Delete an environment var from environ.
  96. ** name is an environment variable <var>. All strings in environ
  97. ** beginning with "<var>=" are deleted from environ. unsetenv
  98. ** returns the number of occurrences it found and deleted; if
  99. ** it returns 0, then the variable wasn't in environ to begin with.
  100. ** If name is the null pointer, unsetenv returns -1 immediately.
  101. */
  102.  
  103. int unsetenv(const char *name)
  104. {
  105.     char **envp, **target;
  106.     int hits;
  107.     int slen;
  108.  
  109.     if( !name ) return -1;
  110.     slen = strlen(name);
  111.     hits = 0;
  112.     target = environ;
  113.  
  114.     for( envp=environ; *envp; envp++ )
  115.     if( !strncmp(*envp, name, slen) && (*envp)[slen] == '=' )
  116.         hits++;
  117.     else
  118.         *target++ = *envp;
  119.     *target = 0;
  120.  
  121.     return hits;
  122.     }
  123.  
  124.  
  125. /* int setenv(const char *name, const char *val)
  126. ************************************************
  127. ** Sets an existing env var or adds a new one.
  128. ** - If val  is the null pointer, the env var is deleted.
  129. ** - If name is the null pointer, setenv() returns an error and does nothing.
  130. **
  131. ** If env var <name> is already defined in environ, then
  132. ** the new value is copied over the var's old value if
  133. ** there is space. Otherwise a fresh string is allocated
  134. ** with malloc. If the var is not defined, then environ
  135. ** is copied to a fresh block of storage, of size one greater,
  136. ** and the new "<name>=<val>" binding installed in that block.
  137. **
  138. ** Returns 0 if it wins.
  139. ** Returns non-zero if there is an error.
  140. */
  141.  
  142. int setenv(const char *name, const char *val)
  143. {
  144.     char **envp;
  145.     char *s;
  146.     int val_len, name_len;
  147.  
  148.     if( !name ) return 1;
  149.     if( !val ) {
  150.     unsetenv(name);
  151.     return 0;
  152.     }
  153.  
  154.     name_len = strlen(name);
  155.     val_len  = strlen(val);
  156.     
  157.     for( envp=environ; *envp; envp++ )
  158.     if( !strncmp(*envp, name, name_len) && (*envp)[name_len] == '=' ) {
  159.         char *equal = name_len + *envp;
  160.  
  161.         if( strlen(equal+1) >= val_len )
  162.         memcpy(equal+1, val, val_len+1); /* Copy in place. */
  163.         else {
  164.         char *s = Malloc(char, name_len + val_len + 2);
  165.         if( !s ) return 1;
  166.         memcpy(s, name, name_len);
  167.         s[name_len] = '=';
  168.         memcpy(s+name_len+1, val, val_len+1);
  169.         *envp=s;
  170.         }
  171.         return 0;
  172.         }
  173.  
  174.     /* Not found. Add. */
  175.     s = Malloc(char, val_len + name_len + 2);
  176.     if( !s ) return 1;
  177.     memcpy(s, name, name_len);
  178.     s[name_len] = '=';
  179.     memcpy(s+name_len+1, val, val_len+1);
  180.     return append_envvar(s, 1+envp-environ);
  181.     }
  182.